/***************************************************************************************************
 *Copyright(C),2010-2017,Sumscope
 *FileName	:  ProtoAdaptor.h
 *Author	:  scofined.qi
 *Version	:  1.0
 *Date		:  2019/01/17
 *Desc		:  //用于主要说明此程序文件完成的主要功能
 *Relation :
 *Others	:  //其他内容说明
 *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
 *History	:
 * //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
 ***************************************************************************************************/
#ifndef PROTOADAPTOR_H_4FDD1B8A_A3F5_4FBB_92DA_6248CDE36278
#define PROTOADAPTOR_H_4FDD1B8A_A3F5_4FBB_92DA_6248CDE36278

#include "message.h"
#include "proto_message.h"
#include "variant.h"

namespace qb {
namespace net {
typedef qb::proto::int8_t int8_t;
typedef qb::proto::uint8_t uint8_t;
typedef qb::proto::uint16_t uint16_t;
typedef qb::proto::int16_t int16_t;
typedef qb::proto::uint32_t uint32_t;
typedef qb::proto::int32_t int32_t;
typedef qb::proto::uint64_t uint64_t;
typedef qb::proto::int64_t int64_t;

class ProtoList {
 public:
  typedef qb::proto::Variant Variant;
  typedef qb::proto::Message::List List;
  typedef qb::proto::Message Message;
  typedef qb::proto::Message::List::iterator iterator;
  typedef qb::proto::Message::List::const_iterator const_iterator;
  friend class ProtoMap;
  friend class ProtoMessage;

 private:
  const List *m_list;

 private:
  ProtoList(const ProtoList &pm) = delete;
  ProtoList &operator=(const ProtoList &pm) = delete;
  void SetList(const List *list) { m_list = list; }

 public:
  ProtoList();
  // ProtoList(const List* list);
  ProtoList(const Variant &v);
  bool RefListFrom(const Message &msg, const char *name);
  const_iterator begin() const;
  const_iterator end() const;
  int size() const { return m_list ? m_list->size() : 0; }
  void clear() { m_list = nullptr; }
};
class ProtoMap {
 public:
  typedef qb::proto::Variant Variant;
  typedef qb::proto::Message::List List;
  typedef qb::proto::VariantMap VariantMap;
  typedef qb::proto::Message Message;
  typedef qb::proto::Message::List::iterator iterator;
  typedef qb::proto::Message::List::const_iterator const_iterator;
  friend class ProtoMessage;

 private:
  const VariantMap *m_map;
  std::vector<ProtoList *> m_reflist;

 private:
  ProtoMap(const ProtoMap &pm) = delete;
  ProtoMap &operator=(const ProtoMap &pm) = delete;
  void SetMap(const VariantMap *map) { m_map = map; }

 public:
  ProtoMap();
  // ProtoMap(const VariantMap* map);
  ProtoMap(const Variant &v);
  ~ProtoMap();
  bool RefList(const char *name, const ProtoList *&pList) const;
  bool RefMapFrom(const Message &msg, const char *name);
  bool GetList(const char *name, ProtoList &list) const;
  bool getList(const char *name, ProtoList &list) const;
  bool GetMap(const char *name, ProtoMap &map) const;
  bool RefString(const char *name, const char *&value, size_t &size) const;
  operator const VariantMap &() const;

#define IMPL_GET_MAP_PROPERTY(NAME, VAL, FUNC) \
  return m_map ? m_map->FUNC(NAME, VAL) : false;
  bool GetBool(const char *name, bool &value) const {
    IMPL_GET_MAP_PROPERTY(name, value, GetBool);
  }
  bool GetUInt8(const char *name, uint8_t &value) const {
    IMPL_GET_MAP_PROPERTY(name, value, GetUInt8);
  }
  bool GetUInt16(const char *name, uint16_t &value) const {
    IMPL_GET_MAP_PROPERTY(name, value, GetUInt16);
  }
  bool GetUInt32(const char *name, uint32_t &value) const {
    IMPL_GET_MAP_PROPERTY(name, value, GetUInt32);
  }
  bool GetUInt64(const char *name, uint64_t &value) const {
    IMPL_GET_MAP_PROPERTY(name, value, GetUInt64);
  }
  bool GetInt8(const char *name, int8_t &value) const {
    IMPL_GET_MAP_PROPERTY(name, value, GetInt8);
  }
  bool GetInt16(const char *name, int16_t &value) const {
    IMPL_GET_MAP_PROPERTY(name, value, GetInt16);
  }
  bool GetInt32(const char *name, int32_t &value) const {
    IMPL_GET_MAP_PROPERTY(name, value, GetInt32);
  }
  bool GetInt64(const char *name, int64_t &value) const {
    IMPL_GET_MAP_PROPERTY(name, value, GetInt64);
  }
  bool GetFloat(const char *name, float &value) const {
    IMPL_GET_MAP_PROPERTY(name, value, GetFloat);
  }
  bool GetDouble(const char *name, double &value) const {
    IMPL_GET_MAP_PROPERTY(name, value, GetDouble);
  }

  inline bool getBool(const std::string &name, bool &value) const {
    return GetBool(name.c_str(), value);
  }
  inline bool getUint8(const std::string &name, uint8_t &value) const {
    return GetUInt8(name.c_str(), value);
  }
  inline bool getUint16(const std::string &name, uint16_t &value) const {
    return GetUInt16(name.c_str(), value);
  }
  inline bool getUint32(const std::string &name, uint32_t &value) const {
    return GetUInt32(name.c_str(), value);
  }
  inline bool getUint64(const std::string &name, uint64_t &value) const {
    return GetUInt64(name.c_str(), value);
  }
  inline bool getInt8(const std::string &name, int8_t &value) const {
    return GetInt8(name.c_str(), value);
  }
  inline bool getInt16(const std::string &name, int16_t &value) const {
    return GetInt16(name.c_str(), value);
  }
  inline bool getInt32(const std::string &name, int32_t &value) const {
    return GetInt32(name.c_str(), value);
  }
  inline bool getInt64(const std::string &name, int64_t &value) const {
    return GetInt64(name.c_str(), value);
  }
  inline bool getFloat(const std::string &name, float &value) const {
    return GetFloat(name.c_str(), value);
  }
  inline bool getDouble(const std::string &name, double &value) const {
    return GetDouble(name.c_str(), value);
  }
};
class ProtoMessage {
  typedef qb::proto::Message Message;
  typedef qb::proto::Message::Raw Raw;
  typedef qb::proto::VariantMap VariantMap;
  const Message *m_message;
  const VariantMap *m_map;  // 参考MessageParser::ExtractData,
                            // 这两个成员只能有一个有效
 public:
  ProtoMessage(const Message &msg);
  ProtoMessage(const ProtoMap &map);
  // bool RefMsgFrom(const Message& msg, const char* name){
  //	msg.getMessage()
  // }
  bool GetList(const char *name, ProtoList &list) const;
  const ProtoMap &MapValue();
  bool GetRaw(const char *name, Raw &value) const;

#define IMPL_GET_PROPERTY(NAME, VAL, FUNC)                    \
  if (m_message == nullptr && m_map == nullptr) return false; \
  return m_message ? m_message->FUNC(NAME, VAL) : m_map->FUNC(NAME, VAL);

  bool getList(const char *name, ProtoList &list) const;
  bool GetMap(const char *name, ProtoMap &map) const;
  bool RefString(const char *name, const char *&value, size_t &size) const;

  bool GetBool(const char *name, bool &value) const {
    IMPL_GET_PROPERTY(name, value, GetBool);
  }
  bool GetUInt8(const char *name, uint8_t &value) const {
    IMPL_GET_PROPERTY(name, value, GetUInt8);
  }
  bool GetUInt16(const char *name, uint16_t &value) const {
    IMPL_GET_PROPERTY(name, value, GetUInt16);
  }
  bool GetUInt32(const char *name, uint32_t &value) const {
    IMPL_GET_PROPERTY(name, value, GetUInt32);
  }
  bool GetUInt64(const char *name, uint64_t &value) const {
    IMPL_GET_PROPERTY(name, value, GetUInt64);
  }
  bool GetInt8(const char *name, int8_t &value) const {
    IMPL_GET_PROPERTY(name, value, GetInt8);
  }
  bool GetInt16(const char *name, int16_t &value) const {
    IMPL_GET_PROPERTY(name, value, GetInt16);
  }
  bool GetInt32(const char *name, int32_t &value) const {
    IMPL_GET_PROPERTY(name, value, GetInt32);
  }
  bool GetInt64(const char *name, int64_t &value) const {
    IMPL_GET_PROPERTY(name, value, GetInt64);
  }
  bool GetFloat(const char *name, float &value) const {
    IMPL_GET_PROPERTY(name, value, GetFloat);
  }
  bool GetDouble(const char *name, double &value) const {
    IMPL_GET_PROPERTY(name, value, GetDouble);
  }
  inline bool getBool(const std::string &name, bool &value) const {
    return GetBool(name.c_str(), value);
  }
  inline bool getUint8(const std::string &name, uint8_t &value) const {
    return GetUInt8(name.c_str(), value);
  }
  inline bool getUint16(const std::string &name, uint16_t &value) const {
    return GetUInt16(name.c_str(), value);
  }
  inline bool getUint32(const std::string &name, uint32_t &value) const {
    return GetUInt32(name.c_str(), value);
  }
  inline bool getUint64(const std::string &name, uint64_t &value) const {
    return GetUInt64(name.c_str(), value);
  }
  inline bool getInt8(const std::string &name, int8_t &value) const {
    return GetInt8(name.c_str(), value);
  }
  inline bool getInt16(const std::string &name, int16_t &value) const {
    return GetInt16(name.c_str(), value);
  }
  inline bool getInt32(const std::string &name, int32_t &value) const {
    return GetInt32(name.c_str(), value);
  }
  inline bool getInt64(const std::string &name, int64_t &value) const {
    return GetInt64(name.c_str(), value);
  }
  inline bool getFloat(const std::string &name, float &value) const {
    return GetFloat(name.c_str(), value);
  }
  inline bool getDouble(const std::string &name, double &value) const {
    return GetDouble(name.c_str(), value);
  }
};
}  // namespace net
}  // namespace qb

namespace qb {
namespace base {
namespace msg {
class ProtoUtil {
 public:
  static bool CheckMessage(const ProtoMessage &msg, const char *buf, int len);
};
}  // namespace msg
}  // namespace base
}  // namespace qb

#define USING_PROTO_ADAPTOR
#ifdef USING_PROTO_ADAPTOR
#define REFMAP_FROM_MSG(MSG, NAME, MAP) MAP.RefMapFrom(MSG, NAME)
#define REFLIST_FROM_MSG(MSG, NAME, LIST) LIST.RefListFrom(MSG, NAME)
#define WrapProtoMsg(MSG) MSG
typedef qb::base::msg::ProtoMap ProtoMap;
typedef qb::base::msg::ProtoList ProtoList;
typedef qb::base::msg::ProtoMessage ProtoMessage;
typedef qb::base::msg::Raw ProtoRaw;
typedef qb::base::msg::Value ProtoValue;
#else
#define REFMAP_FROM_MSG(MSG, NAME, MAP) MSG.GetMap(NAME, MAP)
#define REFLIST_FROM_MSG(MSG, NAME, LIST) MSG.getList(NAME, LIST)
#define WrapProtoMsg(MSG) MSG
typedef qb::proto::Message ProtoMessage;
typedef qb::proto::VariantMap ProtoMap;
typedef qb::proto::Message::List ProtoList;
typedef qb::proto::Message::Raw ProtoRaw;
typedef qb::proto::Variant ProtoValue;

#endif

#endif
